package com.chenjim.architecture.data

import android.content.Context
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class DataStoreHelper @Inject constructor(@ApplicationContext private val context: Context) {

    companion object {
        private val USERNAME = stringPreferencesKey("username")
        private val IS_LOGGED_IN = booleanPreferencesKey("is_logged_in")
    }

    private val Context.dataStore by preferencesDataStore(name = "data_store_prefs")

    suspend fun setLoggedIn(login: Boolean) {
        context.dataStore.edit { preferences ->
            preferences[IS_LOGGED_IN] = login
        }
    }

    suspend fun isLoggedIn(): Boolean {
        return context.dataStore.data.map { preferences ->
            preferences[IS_LOGGED_IN] ?: false
        }.first()
    }

    suspend fun setUserName(username: String) {
        context.dataStore.edit { preferences ->
            preferences[USERNAME] = username
        }
    }

    suspend fun getUserName(context: Context): String {
        return context.dataStore.data.map { preferences ->
            preferences[USERNAME] ?: ""
        }.first()
    }

    suspend fun <T> setValue(key: Preferences.Key<T>, value: T, context: Context) {
        context.dataStore.edit { preferences ->
            @Suppress("UNCHECKED_CAST") when (value) {
                is String -> preferences[key as Preferences.Key<String>] = value
                is Int -> preferences[key as Preferences.Key<Int>] = value
                is Boolean -> preferences[key as Preferences.Key<Boolean>] = value
                is Float -> preferences[key as Preferences.Key<Float>] = value
                is Long -> preferences[key as Preferences.Key<Long>] = value
                else -> throw IllegalArgumentException("Type not supported")
            }
        }
    }

    suspend fun getString(key: Preferences.Key<String>, defValue: String = ""): String {
        return context.dataStore.data.map { preferences ->
            preferences[key] ?: defValue
        }.first()
    }

    suspend fun getInt(key: Preferences.Key<Int>, defValue: Int = 0): Int {
        return context.dataStore.data.map { preferences ->
            preferences[key] ?: defValue
        }.first()
    }

    suspend fun getBoolean(key: Preferences.Key<Boolean>, defValue: Boolean = false): Boolean {
        return context.dataStore.data.map { preferences ->
            preferences[key] ?: defValue
        }.first()
    }

    suspend fun getFloat(
        key: Preferences.Key<Float>, defValue: Float = 0F
    ): Float {
        return context.dataStore.data.map { preferences ->
            preferences[key] ?: defValue
        }.first()
    }

    suspend fun getLong(key: Preferences.Key<Long>, defValue: Long = 0L): Long {
        return context.dataStore.data.map { preferences ->
            preferences[key] ?: defValue
        }.first()
    }

    suspend fun removeKey(key: Preferences.Key<*>) {
        context.dataStore.edit { preferences ->
            preferences.remove(key)
        }
    }

    suspend fun clearAll(context: Context) {
        context.dataStore.edit { preferences ->
            preferences.clear()
        }
    }

}